package com.chatTools.protocol;

import com.chatTools.config.Config;
import com.chatTools.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author： pang-yun
 * @date： 2021-09-16 11:10
 * 功能目的 ：用于  聊天的编解码器
 */

/*
- 魔数                        用来第一时间判断是否是无效数据包
- 版本号                          可以支持协议的升级
- 序列化算法           消息正文到底采用那种序列化和反序列化方式   可以由此扩展 ： json  protobuf   hessian   jdk
- 指令类型             是 登录  注册 单聊  群聊…………   跟业务相关
- 请求序号                为了双工通信    提供异步能力
- 正文长度
- 消息正文      */

/*
 * 正文内容 长度随意  但是 正文之前的 内容应该是  2的整数倍
 * 只有15 个  需要加一个 无意义位 来凑齐 16位
 * */

//   ByteToMessageCodec  -------》》》》》这个父类 已经写死禁止共享
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {
    @Override    //编码    将接收到的消息 编码 放入 bytebuf 中
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {

        // 1. 魔数  4 字节   判断是否为有效数据包
        out.writeBytes(new byte[]{1, 2, 3, 4});
        // 2. 版本号  1 字节 的版本
        out.writeByte(1);
        //3. 用一个字节 代表 序列化 算法  JDK 0   json 1
        //out.writeByte(0);
        // 使用读取配置表
        out.writeByte(Config.getSerializerAlgorithm().ordinal());

        //4. 从 msg 中取出 指令类型  一个字节
        out.writeByte(msg.getMessageType());

        // 5. 请求序号  4 个字节
        out.writeInt(msg.getSequenceId());

        // ----添加一个 无意义字节  对齐填充 满足 二的整数倍
        out.writeByte(0xff);

        // 6. 获取内容的字节数组
       /* ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();*/
        // 调用序列化算法
        // byte[] bytes = Serializer.Algorithm.Java.serializer(msg);
        byte[] bytes = Config.getSerializerAlgorithm().serializer(msg);

        // 7. 长度  4个字节
        out.writeInt(bytes.length);

        // 8. 内容
        out.writeBytes(bytes);


    }

    @Override   //根据  编码规则  解码    将收到的ByteBuf 解码   结果放到  list中
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 获取魔数
        int magicNum = in.readInt();
        //  获取版本
        byte version = in.readByte();
        // 获取序列化方式
        byte serializerType = in.readByte();
        // 获取指令类型
        byte messageType = in.readByte();
        // 获取消息序号
        int sequenceId = in.readInt();
        // 获取 无意义 字节
        byte b = in.readByte();
        // 获取长度
        int length = in.readInt();
        // 分配 内容长度的数组  准备读取内容
        byte[] bytes = new byte[length];

        // 读取 消息内容的长度
        in.readBytes(bytes, 0, length);

        Message message = null;
        // 如果序列化类型是 jdk
        // if (serializerType == 0) {
        // 开始反序列化   ObjectInputStream  反序列化流
           /* ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
            message = (Message) ois.readObject();*/

        // 调用反序列化算法
        //  Serializer.Algorithm.Java.deserializer(Message.class,bytes);

        //-------------直接使用 这个会报错 需要找到 实现类  json 实现时 需要返回具体的实现类
        //Serializer.Algorithm.values()[serializerType].deserializer(Message.class,bytes);
        // 首先要找到反序列化算法
        Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializerType];
        //确定具体的消息类型
        Class<?> aClass = Message.getMessageClass(messageType);
        Object deserializer = algorithm.deserializer(aClass, bytes);

        //   }

        //----------将解析出的结果打印
        log.info("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
        log.info("{}", message);


        // 将解析的结果放入 list中  准备给下一个 handler 使用
        // out.add(message);
        out.add(deserializer);


    }
}
